﻿using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System.IO;
using System.Windows;
using System.Windows.Forms;
using VIA.Foundation;
using VIA.ImageProcessing;
using VIA.Integration;
using VIA.Integration.Domain;
using VIA.Integration.Domain.Production;
using VIA.Presentation;
using VIA.Presentation.Contracts;
using VIA.Project.Domain.Services;
using VIA.SiMoJi.Domain.Inspection;
using VIA.SiMoJi.Domain.Option;
using VIA.VTPlatformService;
using VIA.SiMoJi.Domain.Vision;
using VIA.SiMoJi.Domain.Electronics;
using PropertyChanged;
using System.Collections.ObjectModel;
using System.Threading;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using VIA.RbacPassport;
using VIA.Presentation.Services;
using WPFLocalizeExtension.Extensions;
using NPOI.SS.Formula.Functions;
using System.Windows.Threading;

namespace VIA.Project.Presentation.ViewModel.Inspection
{
    [ViewModel(typeof(IParamView))]
    internal class ParamViewModel : ViewModel<IParamView>
    {
        #region Filed
        readonly Inspector _inspector;
        readonly ICommandFactory _commandFactory;
        readonly IOptionRepository _optionRepository;
        readonly IMessageService _messageService;
        readonly ILogger _logger;
        readonly IDispatcherService _dispatcherService;
        readonly ICurrentRecipe _currentRecipe;
        readonly IFileDialogService _fileDialogService;
        readonly IVTPlatformManager _platformManager;
        readonly IDetectionContextFactory _detectionContextFactory;
        readonly ICsvStorageService _csvStorageService;
        private bool isRunning;
        private CancellationTokenSource _cancellationTokenSource = new();
        private VisionStation _station;
        private VisionStationOption _visionoption;
        private InspectorOption _option;
        private CardIoPointModel selectedInputPointModel;
        private CardIoPointModel selectedOutputPointModel;
        private bool isRefresh;
        private ICurrentUser _currentUser;
        int _ngTrayRow;
        int _ngTrayCol;
        double _ngTrayRowDis;
        double _ngTrayColDis;
        private bool isOperateEnable;
        private bool isManualMode;
        private bool isDoorVisibility;
        #endregion

        #region Property
        public Electronic Electronic => Electronic.Default;
        public bool IsRunning { get => isRunning; private set => SetProperty(ref isRunning, value); }
        public VisionStationOption VisionOption { get => _visionoption; set { SetProperty(ref _visionoption, value); } }
        public InspectorOption Option { get => _option; set => SetProperty(ref _option, value); }
        public ObservableCollection<CardIoPointModel> InputPointModels { get; set; } = new();
        public ObservableCollection<CardIoPointModel> OutputPointModels { get; set; } = new();
        public CardIoPointModel SelectedInputPointModel { get => selectedInputPointModel; set => SetProperty(ref selectedInputPointModel, value); }
        public CardIoPointModel SelectedOutputPointModel { get => selectedOutputPointModel; set => SetProperty(ref selectedOutputPointModel, value); }
        public bool IsManualMode { get => isManualMode; set => SetProperty(ref isManualMode, value); }
        public bool IsDoorVisibility { get => isDoorVisibility; set => SetProperty(ref isDoorVisibility, value); }
        public bool IsOperateEnable
        {
            get => isOperateEnable;
            set => SetProperty(ref isOperateEnable, value);
        }
        public bool IsRefresh
        {
            get => isRefresh;
            set
            {

                if (SetProperty(ref isRefresh, value))
                {
                    if (value)
                    {
                        IORefresh();
                    }
                    else
                    {
                        _cancellationTokenSource?.Cancel();
                    }

                }
            }
        }

        public IRelayCommand SaveCommand { get; set; }
        public IRelayCommand CancelCommand { get; set; }
        public IRelayCommand RemoveCommand { get; set; }
        public IRelayCommand EditorCommand { get; set; }
        public IRelayCommand SelectCommand { get; set; }
        public IRelayCommand SelectFileCommand { get; set; }
        public IRelayCommand RunCommand { get; set; }
        public IRelayCommand RefreshCommand { get; set; }
        public IRelayCommand SetOutputValueCommand { get; set; }
        public IRelayCommand ReadLoadTrayCommand { get; set; }
        public IRelayCommand SaveLoadTrayCommand { get; set; }
        public IRelayCommand ReadUnloadNGTrayCommand { get; set; }
        public IRelayCommand SaveUnloadNGTrayCommand { get; set; }
        public IRelayCommand TestCommand { get; set; }


        #endregion

        public ParamViewModel(IServiceProvider service, Inspector inspector)
        {
            _logger = service.GetService<ILogger<ParamViewModel>>();
            _inspector = inspector;
            _station = inspector.VisionStation;
            _currentUser = service.GetService<ICurrentUser>();
            _currentUser.UserChanged += CurrentUser_UserChanged;
            _inspector.ManualAutoStateChanged += Inspector_ManualAutoStateChanged;
            _messageService = service.GetRequiredService<IMessageService>();
            _commandFactory = service.GetRequiredService<ICommandFactory>();
            _fileDialogService = service.GetRequiredService<IFileDialogService>();
            _detectionContextFactory = service.GetRequiredService<IDetectionContextFactory>();
            _optionRepository = service.GetRequiredService<IOptionRepository>();
            _platformManager = service.GetRequiredService<IVTPlatformManager>();
            _dispatcherService = service.GetRequiredService<IDispatcherService>();
            _csvStorageService = service.GetRequiredService<ICsvStorageService>();
            _currentRecipe = service.GetRequiredService<ICurrentRecipe>();
            _currentRecipe.OnRecipeChanged -= CurrentRecipe_OnRecipeChanged;
            InitIOPoint();
            Option = _optionRepository.Get<InspectorOption>();
            SaveCommand = _commandFactory.Create(Save, () => _currentUser.IsGranted(PermissionProvider.SaveDoorParam));
            CancelCommand = _commandFactory.Create(Cancel);
            SelectFileCommand = _commandFactory.Create(SelectFile);
            RunCommand = _commandFactory.Create(Run);
            ReadLoadTrayCommand = _commandFactory.Create(ReadLoadTray);
            SaveLoadTrayCommand = _commandFactory.Create(SaveLoadTray);
            ReadUnloadNGTrayCommand = _commandFactory.Create(ReadUnloadNGTray);
            SaveUnloadNGTrayCommand = _commandFactory.Create(SaveUnloadNGTray);
            TestCommand = _commandFactory.Create(Test);
            //SetOutputValueCommand = _commandFactory.Create(SetOutputValue);
            //RefreshCommand = _commandFactory.Create(Refresh);
        }

        public void Test()
        {
            Task.Factory.StartNew(() =>
            {
                IsOperateEnable = !IsOperateEnable;
            });
        }

        private void CurrentUser_UserChanged(object sender, UserChangedEventArgs e)
        {
            SaveCommand.RaiseCanExecuteChanged();
            CheckOperateEnable();
        }
        private void Inspector_ManualAutoStateChanged(object sender, ManualAutoStateChangedEventArgs e)
        {
            IsManualMode = e.State == EquipmentManualAutoState.Manual;
            CheckOperateEnable();
        }

        private void CheckOperateEnable()
        {
            IsDoorVisibility = _currentUser.IsGranted(PermissionProvider.SaveDoorParam) && IsManualMode && !Electronic.Default.GetIsAutoRun();
            IsOperateEnable = _currentUser.IsGranted(PermissionProvider.SettingParamEnable) && IsManualMode && !Electronic.Default.GetIsAutoRun();
        }

        int _feedTrayRow;
        int _feedTrayCol;
        double _feedTrayRowDis;
        double _feedTrayColDis;
        public int FeedTrayRow
        {
            get => _feedTrayRow;
            set => SetProperty(ref _feedTrayRow, value);
        }
        public int FeedTrayCol
        {
            get => _feedTrayCol;
            set => SetProperty(ref _feedTrayCol, value);
        }
        public double FeedTrayRowDis
        {
            get => _feedTrayRowDis;
            set => SetProperty(ref _feedTrayRowDis, value);
        }
        public double FeedTrayColDis
        {
            get => _feedTrayColDis;
            set => SetProperty(ref _feedTrayColDis, value);
        }
        void ReadLoadTray()
        {
            FeedTrayRow = FeedTray.Instance.Row;
            FeedTrayCol = FeedTray.Instance.Col;
            FeedTrayRowDis = FeedTray.Instance.RowDistance;
            FeedTrayColDis = FeedTray.Instance.ColDistance;
        }
        void SaveLoadTray()
        {
            var result = _messageService.ShowYesNoQuestion("是否保存参数");
            if (result)
            {
                FeedTray.Instance.Row = FeedTrayRow;
                FeedTray.Instance.Col = FeedTrayCol;
                FeedTray.Instance.RowDistance = FeedTrayRowDis;
                FeedTray.Instance.ColDistance = FeedTrayColDis;
                FeedTray.Instance.Save();
            }
        }

        public int NGTrayRow
        {
            get => _ngTrayRow;
            set => SetProperty(ref _ngTrayRow, value);
        }
        public int NGTrayCol
        {
            get => _ngTrayCol;
            set => SetProperty(ref _ngTrayCol, value);
        }
        public double NGTrayRowDis
        {
            get => _ngTrayRowDis;
            set => SetProperty(ref _ngTrayRowDis, value);
        }
        public double NGTrayColDis
        {
            get => _ngTrayColDis;
            set => SetProperty(ref _ngTrayColDis, value);
        }
        void ReadUnloadNGTray()
        {
            NGTrayRow = NGTray.Instance.Row;
            NGTrayCol = NGTray.Instance.Col;
            NGTrayRowDis = NGTray.Instance.RowDistance;
            NGTrayColDis = NGTray.Instance.ColDistance;
        }

        void SaveUnloadNGTray()
        {
            var result = _messageService.ShowYesNoQuestion("是否保存参数");
            if (result)
            {
                NGTray.Instance.Row = NGTrayRow;
                NGTray.Instance.Col = NGTrayCol;
                NGTray.Instance.RowDistance = NGTrayRowDis;
                NGTray.Instance.ColDistance = NGTrayColDis;
                NGTray.Instance.Save();
            }
        }

        private void IORefresh()
        {
            _cancellationTokenSource?.Cancel();
            _cancellationTokenSource = new CancellationTokenSource();
            Task.Factory.StartNew(async () =>
            {
                while (!_cancellationTokenSource.Token.IsCancellationRequested)
                {
                    View.Dispatcher.Invoke(() =>
                    {
                        InputPointModels.ForEach(x => x.Refresh());
                        OutputPointModels.ForEach(x => x.Refresh());
                    });
                    await Task.Delay(100);
                }
            }, TaskCreationOptions.LongRunning);
        }

        private void InitIOPoint()
        {
            foreach (var item in Electronic.InputPoints2)
            {
                InputPointModels.Add(new CardIoPointModel(item.Key, item.Value, false));
            }

            foreach (var item in Electronic.OutputPoints2)
            {
                OutputPointModels.Add(new CardIoPointModel(item.Key, item.Value, true));
            }
        }

        private void Run()
        {
        }

        private void SelectFile()
        {
            FolderBrowserDialog dialog = new FolderBrowserDialog();
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                VisionOption.SelectedFile = dialog.SelectedPath;
            }
        }

        private void CurrentRecipe_OnRecipeChanged(object? sender, RecipeChangedEventArgs e)
        {
            OnViewLoaded();
        }

        protected override void OnViewLoaded()
        {
            IsRunning = _inspector.RunState == RunState.Running;
            VisionOption = _currentRecipe.Get<VisionStationOption>(_station.Id);
            Option = _optionRepository.Get<InspectorOption>();
            _cancellationTokenSource?.Cancel();
            _cancellationTokenSource = new();
            //IORefresh();
            ReadLoadTray();
            ReadUnloadNGTray();
        }


        private async void Save()
        {
            try
            {
                _currentRecipe.Set(_station.Id, VisionOption);
                _optionRepository.Set(Option);
                await _currentRecipe.SaveAsync().ConfigureAwait(continueOnCapturedContext: false);
                await _optionRepository.SaveAsync();
                _messageService.ShowMessage("保存成功！");

            }
            catch (Exception ex)
            {
                _messageService.ShowError(View, "保存失败" + ex.Message);
                _logger.LogError(ex.Message, ex);
            }
        }

        private void Cancel()
        {
            if (System.Windows.MessageBox.Show("放弃已做出的修改?", "提示！", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
            {
                OnViewLoaded();
            }
        }

        public class CardIoPointModel : Model
        {
            public string Name { get; }
            //public bool Data { get => data; set { SetProperty(ref data, value); } }
            public bool Data
            {
                get => Point.Value;
                set
                {
                    Point.Value = value;
                    Thread.Sleep(5);
                    RaisePropertyChanged(nameof(Data));
                }
            }
            public bool IsOutputEnable { get; }
            public CardIoPoint Point { get; }
            public CardIoPointModel() { }
            public CardIoPointModel(string name, CardIoPoint point, bool isOutputEnabel)
            {
                Name = name;
                Point = point;
                IsOutputEnable = isOutputEnabel;
            }


            public void Refresh()
            {
                RaisePropertyChanged(nameof(Data));
            }
        }
    }
}
